package netty.aio;

import cn.hutool.core.util.CharsetUtil;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * @program NettyLeaning
 * @description:
 * @author: zhanglu
 * @create: 2022-01-19 00:20:00
 */
@Slf4j
public class TimeClient {

    private static final String IP = "127.0.0.1";
    private static final Integer PORT = 8080;

    @Test
    public void client() throws Exception {
        new Thread(new AsyncTimeClientHandler(IP, PORT)).start();
        while (true){
            TimeUnit.MICROSECONDS.sleep(100);
        }
    }

    public class AsyncTimeClientHandler implements CompletionHandler<Void, AsyncTimeClientHandler>, Runnable{

        private AsynchronousSocketChannel client;
        private String ip;
        private Integer port;
        private CountDownLatch latch;

        public AsyncTimeClientHandler(String ip, Integer port) throws Exception {
            this.ip = ip;
            this.port = port;
            client = AsynchronousSocketChannel.open();
        }

        @Override
        public void run() {
            latch = new CountDownLatch(1);
            client.connect(new InetSocketAddress(ip, port), this, this);
            try {
                latch.await();
                client.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        @Override
        public void completed(Void result, AsyncTimeClientHandler attachment) {
            byte[] req = "hello lu".getBytes();
            ByteBuffer writeBuffer = ByteBuffer.allocate(1024);
            writeBuffer.put(req);
            writeBuffer.flip();
            client.write(writeBuffer, writeBuffer, new CompletionHandler<Integer, ByteBuffer>() {
                @Override
                public void completed(Integer result, ByteBuffer buffer) {
                    if(buffer.hasRemaining()){
                        client.write(buffer, buffer, this);
                    }else {
                        ByteBuffer readBuffer = ByteBuffer.allocate(1024);
                        client.read(readBuffer, readBuffer, new CompletionHandler<Integer, ByteBuffer>() {
                            @Override
                            public void completed(Integer result, ByteBuffer buffer) {
                                buffer.flip();
                                byte[] bytes = new byte[buffer.remaining()];
                                buffer.get(bytes);
                                try {
                                    String body = new String(bytes, CharsetUtil.UTF_8);
                                    log.info(body);
                                    latch.countDown();
                                } catch (UnsupportedEncodingException e) {
                                    e.printStackTrace();
                                }

                            }
                            @Override
                            public void failed(Throwable exc, ByteBuffer attachment) {
                                try {
                                    client.close();
                                    latch.countDown();
                                } catch (IOException e) {
                                    e.printStackTrace();
                                }
                            }
                        });
                    }
                }
                @Override
                public void failed(Throwable exc, ByteBuffer attachment) {
                    try {
                        client.close();
                        latch.countDown();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            });
        }

        @Override
        public void failed(Throwable exc, AsyncTimeClientHandler attachment) {
            exc.printStackTrace();
            try {
                client.close();
                latch.countDown();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}
